package com.snow.starter.global;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import com.snow.exception.CommonException;
import com.snow.exception.CommonMessageRuntimeException;
import com.snow.exception.CommonRuntimeException;
import com.snow.exception.LoginUserNotFoundException;
import com.snow.view.IWebResponse;
import com.snow.view.WebResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.validation.ValidationException;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 *
 * @author by 13119
 */
@Slf4j
@ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {

    public GlobalExceptionHandler() {
        log.debug("全局异常处理器已注入");
    }

    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(LoginUserNotFoundException.class)
    public IWebResponse authFailedException(LoginUserNotFoundException exception) {
        log.debug("当前操作需要获取登录用户，您还未登录或登录已过期:{}", exception.getMessage(), exception);
        return WebResponse.fail(HttpStatus.UNAUTHORIZED.value(), "未登录");
    }

    @ExceptionHandler(SQLException.class)
    public IWebResponse commonSQLException(SQLException exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.error("[{}]服务器内部发生数据库交互异常，请及时处理:{}", errorCode, exception.getMessage(), exception);
        return WebResponse.fail("【" + errorCode + "】服务器内部发生数据库异常，请联系管理员处理");
    }

    @ExceptionHandler(CommonException.class)
    public IWebResponse commonException(CommonException exception) {
        log.error("服务器内部发生运行时异常，请及时处理:{}", exception.getMessage(), exception);
        return WebResponse.fail(exception.getMessage());
    }

    @ExceptionHandler(CommonMessageRuntimeException.class)
    public IWebResponse commonMessageRuntimeException(CommonMessageRuntimeException exception) {
        log.error("服务器内部发生运行时异常，请及时处理:{}", exception.getMessage(), exception);
        return WebResponse.fail(exception.getMessage());
    }

    @ExceptionHandler(CommonRuntimeException.class)
    public IWebResponse commonRuntimeException(CommonRuntimeException exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.warn("【{}】服务器内部发生错误，请及时处理:{}", errorCode, exception.getMessage(), exception);
        return WebResponse.fail("【" + errorCode + "】" + exception.getMessage());
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public IWebResponse httpMessageNotReadableException(HttpMessageNotReadableException exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.debug("【{}】请求异常,请检查出入参错误原因:{}", errorCode, exception.getMessage(), exception);
        return WebResponse.fail("【" + errorCode + "】无法读取请求数据");
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public IWebResponse methodArgumentNotValidException(MissingServletRequestParameterException exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.debug("【" + errorCode + "】请求异常,请检查出入参错误原因:" + exception.getMessage(), exception);
        return WebResponse.fail("【" + errorCode + "】参数校验失败");
    }

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public IWebResponse maxUploadSizeExceededException(MaxUploadSizeExceededException exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.debug("【" + errorCode + "】请求异常,请检查出入参错误原因:" + exception.getMessage(), exception);
        return WebResponse.fail("【" + errorCode + "】文件过大，服务器无法处理");
    }


    @ExceptionHandler(ValidationException.class)
    public IWebResponse constraintViolationException(ValidationException exception) {
        String message = exception.getMessage();
        if (!ReUtil.contains("[\u4e00-\u9fa5]", message)) {
            log.warn("请求内容错误：", exception);
            return WebResponse.fail("请求内容错误，请检查或联系管理员");
        }
        log.warn("请求内容错误：", exception);
        return WebResponse.fail(message);
    }

    @ExceptionHandler(BindException.class)
    public IWebResponse bindException(BindException exception) {
        List<ObjectError> errors = exception.getBindingResult().getAllErrors();
        String message = errors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","));
        if (!ReUtil.contains("[\u4e00-\u9fa5]", message)) {
            log.warn("请求内容错误：", exception);
            return WebResponse.fail("请求内容错误，请检查或联系管理员");
        }
        return WebResponse.fail(message);
    }

    @ExceptionHandler(RuntimeException.class)
    public IWebResponse runtimeException(RuntimeException exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.error("【{}】服务器内部发生运行时异常，请及时处理:{}", errorCode, exception.getMessage(), exception);
        return WebResponse.fail("【" + errorCode + "】服务器内部发生运行时异常，请联系管理员");
    }

    @ExceptionHandler(Exception.class)
    public IWebResponse exception(Exception exception) {
        String errorCode = RandomUtil.randomNumbers(6);
        log.error("【{}】服务器内部发生未知异常，请及时处理:{}", errorCode, exception.getMessage(), exception);
        return WebResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), "【" + errorCode + "】服务器内部异常，请尽快反馈管理员处理");
    }

}
